package twobarOpt;

import core_masterworker.Worker;
import inf.minife.fe.Model;
import utils.MWUtils;
import data.*;
import model.TwoBar;
import mpi.MPI;
import mpi.Status;

public class TwoBarRSWorker extends Worker {

	/* Tag information between master - worker */
	public MWUtils mwutils = new MWUtils();
	int work_tag = mwutils.WORK_TAG;
	int data_tag = mwutils.DATA_TAG;
	int stop_tag = mwutils.STOP_TAG;
	
	public TwoBarRSWorker(int id_) {
		super(id_);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void doWork() {
		// TODO Auto-generated method stub
		
	}

	public void doWork(int myid, int master, int design_number, double sigmaMax,
			double uMax, TwoBar twobar, int result_number, RSData[] rsdata) {
		// TODO Auto-generated method stub
		
		Status status;
		boolean done = false;		
		
		/* Store data */
		int cid = 0;
		

		/* Set up for dynamic assignment */
		DataTest[] count = new DataTest[1];
		count[0] = new DataTest(cid);	
		
		/* Initiate result worker send to master */
		DataTest[] result = new DataTest[result_number];
		
		/* Init result */
		for(int i = 0; i < result.length; i++){
			result[i] = new DataTest(0);			
		}
		
		/* rsdata array store init, lower, upper values of H value and b1, b2 diameter of 2 bar */
		
		/* Init a double array to store new cross section area values */
		double[] x = new double[design_number];		
		
		while(done != true){
			status = MPI.COMM_WORLD.Recv(count, 0, count.length, MPI.OBJECT, master, MPI.ANY_TAG);
			
			/* Checking received data */
			int the_row = (int)count[0].getDataInt();
			System.out.println("Receive count at = " + the_row);
			System.out.println("Worker number = " + myid);
			System.out.println("Tag = " + status.tag + " from source = " + status.source);
			
			if(status.tag == stop_tag){
				done = true;
				break;
			}		

			
			/*
			 * Randomly generate H value, b1, b2 diameter value
			 * then pass to TwoBar model to check fitness value
			 * mass value and constrain conditions
			 */		    
		
			
	    	/* Randomly get a value from the list of cross section area pass to x array */
	    	for (int j = 0; j < design_number; j++) {
	    		
	    		/* Get upper and lower value, then randomly generate new value, pass to x array */
	    		double hight_val = rsdata[j].getUpper();
	    		double low_val = rsdata[j].getLower();	    		
	    		double temp = mwutils.random(hight_val, low_val);
	    		
	    		x[j] = temp;
	            System.out.print("[" + temp + "] " );         
	        }
	    	
	    	/* Update to plane truss and calculate */
	    	Model evaluation = new Model();
	    	evaluation = twobar.getModel();
	    	evaluation = twobar.createModel(evaluation,x);
	    	evaluation.solve();
	    	double mass_new = evaluation.getTotalMass();
	    	System.out.println("New mass value = " + mass_new);
	    	
	    	/* Check fitness condition 
	    	 * Function: F(x) = 1/f(x)[1000v + 1]
	    	 * with f(x) = total mass
	    	 */
	    	
	    	/* Normalize form of stress constrain
	    	 * sigma(j)/sigmaMax - 1 <= 0
	    	 */
	    	/* Check violation stress constrains */
	    	double[] fcheck = mwutils.computeStressConstrains(evaluation, sigmaMax);
	    	double countviolation = 0;
	    	for(int j = 0; j < fcheck.length; j++){
	    		if(fcheck[j] > 0) countviolation++;
	    	}
	    	
	    	/* Normalize form of displacement constrain
	    	 * u(j)/uMax - 1 <= 0
	    	 */
	    	/* Check violation stress constrains */
	    	/* Check violation displacement constrains */
	    	double[] gxcheck = mwutils.computeDispXConstrains(evaluation, uMax);
	    	
	    	for(int j = 0; j < gxcheck.length; j++){
	    		if(gxcheck[j] > 0) countviolation++;
	    	}
	    	double[] gycheck = mwutils.computeDispYConstrains(evaluation, uMax);
	    	
	    	for(int j = 0; j < gycheck.length; j++){
	    		if(gycheck[j] > 0) countviolation++;
	    	}
	    	System.out.println("Number of violation constrains = " + countviolation);
	    	
	    	/* Calculate fitness value */
	    	double fitvalue = 1/((1000.0*countviolation + 1)*mass_new);
	    	//genetic_experiment.setFitnessValue(fitvalue);
	    
	    	//System.out.println("Generation's fitness value = " + genetic_experiment.getFitnessValue());
	    	System.out.println();
	    	
	    	/* Store values
	    	 * no of generation
	    	 * number of violation constrain
	    	 * fitness value
	    	 * mass value
	    	 * to send back to master
	    	 */
	    	try{
	    		result[0].updateData(the_row);
				result[1].updateData(countviolation);
				result[2].updateData(fitvalue);
				result[3].updateData(mass_new);
	    	}
	    	catch (IndexOutOfBoundsException e) {
				System.out.println("Index out of boundary! Check use in result array length");
				return;
			}
			catch (NullPointerException e) {
				System.out.println("Result array is null pointer! Init before use");
				return;
			}
			
			/* Send result to master */
			MPI.COMM_WORLD.Send(result, 0, result.length, MPI.OBJECT, master, data_tag);
		}
	}

}
